#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "./bsl_string.h"

namespace BSL
{
    int bsl_replace_char(char *pszStr, char dst, char src)
    {
        if (pszStr == NULL)
        {
            return -1;
        }

        int cnt = 0;
        while (*pszStr)
        {
            if (*pszStr == src)
            {
                cnt++;
                *pszStr = dst;
            }

            pszStr++;
        }

        return cnt;
    }

    int bsl_find_str(const char *src, const char *dst, const unsigned int pos)
    {
        int i, j;
        for (i = pos; src[i] != '\0'; i++)
        {
            if (src[i] != dst[0])
                continue;

            j = 0;
            while (dst[j] != '\0' && src[i + j] != '\0')
            {
                j++;
                if (dst[j] != src[i + j])
                    break;
            }
            if (dst[j] == '\0')
                return i;
        }
        return -1;
    }

    int bsl_split_str(const char *str, const char *symbol, char** out)
    {
        if (str == NULL)
        {
            return 0;
        }

        int len = strlen(symbol);
        int i = bsl_find_str(str, symbol);
        int j = 0, c = 0;
        while (i >= 0)
        {
            strncpy(out[c], (str+j), (i-j));
            out[c][i - j] = '\0';
            c++;
            j = i + len;
            i = bsl_find_str(str, symbol, j);
        }
        
        if (strlen(str + j) > 0)
        {
            strncpy(out[c], (str + j), (strlen(str) - j));
            out[c][strlen(str) - j] = '\0';
            c++;
        }

        return c;
    }

    int bsl_split_str(std::string src,
                      std::vector<std::string> &dst,
                      const char symbol)
    {
        if (src.length() == 0)
        {
            return 0;
        }

        if (src.at(0) == symbol)
        {
            src.erase(0, 0);
        }

        if (src.at(src.length() - 1) != symbol)
        {
            src.push_back(symbol);
        }

        size_t pos = src.find(symbol);
        while (pos != std::string::npos)
        {
            size_t len = src.length();
            if (pos >= 1)
            {
                std::string temp = src.substr(0, pos);
                dst.push_back(temp);
            }

            if (pos == len)
            {
                break;
            }

            src = src.substr(pos + 1, len);
            pos = src.find(symbol);
        }

        return dst.size();
    }

    int bsl_split_str_with_escape(const char *str, const char symbol, char** out)
    {
        if (str == NULL || strlen(str) == 0)
        {
            return 0;
        }

        int c = 0;
        while (*str)
        {
            if (*str == '\\')
            {
                *(out[c]++) = *(++str);
            }
            else if (*str == symbol)
            {
                *(out[c]++) = '\0';
                c++;
            }
            else
            {
                *(out[c]++) = *str;
            }

            str++;
        }

        *(out[c]) = '\0';
        if (*(str - 1) != symbol)
        {
            c++;
        }
        return c;
    }

    int bsl_split_uint8_from_str(const char *str,
                                 const char *symbol,
                                 unsigned char arr[],
                                 unsigned int size)
    {
        if (size > 256 || str == NULL || symbol == NULL)
        {
            return -1;
        }

        char szBuf[256][16] = { 0 };
        char *p[256] = { NULL };
        for (int i = 0; i < 256; i++)
        {
            p[i] = szBuf[i];
        }

        int cnt = bsl_split_str(str, symbol, p);
        if (cnt > size) cnt = size;

        for (int i = 0; i < cnt; i++)
        {
            arr[i] = (unsigned char)atoi(szBuf[i]);
        }

        return cnt;
    }

    int bsl_split_uint32_from_str(const char *str,
                                  const char *symbol,
                                  unsigned int arr[],
                                  unsigned int size)
    {
        if (size > 256 || str == NULL || symbol == NULL)
        {
            return -1;
        }

        char szBuf[256][16] = { 0 };
        char *p[256] = { NULL };
        for (int i = 0; i < 256; i++)
        {
            p[i] = szBuf[i];
        }

        int cnt = bsl_split_str(str, symbol, p);
        if (cnt > size) cnt = size;

        for (int i = 0; i < cnt; i++)
        {
            arr[i] = atoll(szBuf[i]);
        }

        return cnt;
    }

    int bsl_split_int64_from_str(const char *str,
                                 const char *symbol,
                                 long long arr[],
                                 unsigned int size)
    {
        if (size > 256 || str == NULL || symbol == NULL)
        {
            return -1;
        }

        char szBuf[256][16] = { 0 };
        char *p[256] = { NULL };
        for (int i = 0; i < 256; i++)
        {
            p[i] = szBuf[i];
        }

        int cnt = bsl_split_str(str, symbol, p);
        if (cnt > size) cnt = size;

        for (int i = 0; i < cnt; i++)
        {
            arr[i] = atoll(szBuf[i]);
        }

        return cnt;
    }

    int bsl_split_str_32(char out[][32], const char *str, char symbol)
    {
        if (str == NULL || out == NULL || *out == NULL)
        {
            return -1;
        }

        int cnt = 0;
        int len = 0;
        while (*str)
        {
            if (*str == symbol)
            {
                if (len > 0)
                {
                    if (len < 32)
                    {
                        memcpy(out[cnt], str - len, len);
                        out[cnt][len] = '\0';
                        cnt++;
                    }
                    len = 0;
                }
                str++;
                continue;
            }

            len++;
            str++;
        }

        if (len > 0 && len < 32)
        {
            memcpy(out[cnt], str - len, len);
            out[cnt][len] = '\0';
            cnt++;
        }

        return cnt;
    }

    void bsl_trim(char *str)
    {
        int _len = strlen(str);
        if (_len < 1)
        {
            return;
        }
        int _begin = 0, _end = _len - 1;
        for (_begin; _begin < _len; _begin++)
        {
            if (!bsl_is_space(str[_begin]))
            {
                break;
            }
        }
        for (_end; _end >= 0; _end--)
        {
            if (!bsl_is_space(str[_end]))
            {
                break;
            }
        }
        int _out_len = _end - _begin + 1;
        if (_out_len > 0)
        {
            memmove(str, str + _begin, _out_len);
        }
        else
        {
            _out_len = 0;
        }
        str[_out_len] = '\0';
    }

    bool bsl_is_space(char c)
    {
        return (c == ' ' || c == '\t' ||
                c == '\n' || c == '\r' ||
                c == '\b' || c == '\f' ||
                c == '\v');
    }

    /*
    UTF-8是一种变长字节编码方式。对于某一个字符的UTF-8编码，如果只有一个字节则其最高二进制位为0；
    如果是多字节，其第一个字节从最高位开始，连续的二进制位值为1的个数决定了其编码的位数，其余各字节均以10开头。
    UTF-8最多可用到6个字节。
    如表：
    1字节 0xxxxxxx
    2字节 110xxxxx 10xxxxxx
    3字节 1110xxxx 10xxxxxx 10xxxxxx
    4字节 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
    5字节 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
    6字节 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
    因此UTF-8中可以用来表示字符编码的实际位数最多有31位，即上表中x所表示的位。除去那些控制位（每字节开头的10等），
    这些x表示的位与UNICODE编码是一一对应的，位高低顺序也相同。
    */
    int bsl_utf8_str_len(const char *str)
    {
        int _offside = 1, _count = 0;
        for (int i = 0; i < strlen((char*)str); i += _offside)
        {
            unsigned char _tmp_c = (unsigned char)str[i];
            if (0 < _tmp_c && _tmp_c < 128)
            {
                _offside = 1;
                ++_count;
            }
            else if (192 <= _tmp_c && _tmp_c < 224)
            {
                _offside = 2;
                _count += 2;
            }
            else if (224 <= _tmp_c && _tmp_c < 240)
            {
                _offside = 3;
                _count += 2;
            }
            else if (240 <= _tmp_c && _tmp_c < 248)
            {
                _offside = 4;
                _count += 2;
            }
            else if (248 <= _tmp_c && _tmp_c < 252)
            {
                _offside = 5;
                _count += 2;
            }
            else if (252 <= _tmp_c && _tmp_c < 256)
            {
                _offside = 6;
                _count += 2;
            }
            else
            {
                //10xxxxxx段的理论上来说属于某个字符的一部分，不做处理
            }
        }
        return _count;
    }

    int bsl_utf8_char_cnt(const char *str)
    {
        int _offside = 1, _count = 0;
        for (int i = 0; i < strlen((char*)str); i += _offside)
        {
            unsigned char _tmp_c = (unsigned char)str[i];
            if (0 < _tmp_c && _tmp_c < 128)
            {
                _offside = 1;
                ++_count;
            }
            else if (192 <= _tmp_c && _tmp_c < 224)
            {
                _offside = 2;
                ++_count;
            }
            else if (224 <= _tmp_c && _tmp_c < 240)
            {
                _offside = 3;
                ++_count;
            }
            else if (240 <= _tmp_c && _tmp_c < 248)
            {
                _offside = 4;
                ++_count;
            }
            else if (248 <= _tmp_c && _tmp_c < 252)
            {
                _offside = 5;
                ++_count;
            }
            else if (252 <= _tmp_c && _tmp_c < 256)
            {
                _offside = 6;
                ++_count;
            }
            else
            {
                //10xxxxxx段的理论上来说属于某个字符的一部分，不做处理
            }
        }
        return _count;
    }

    unsigned char bsl_utf8_char_off_len(unsigned char bChar)
    {
        unsigned char bOffLen = 1;
        if (0 < bChar && bChar < 128)
        {
            bOffLen = 1;
        }
        else if (192 <= bChar && bChar < 224)
        {
            bOffLen = 2;
        }
        else if (224 <= bChar && bChar < 240)
        {
            bOffLen = 3;
        }
        else if (240 <= bChar && bChar < 248)
        {
            bOffLen = 4;
        }
        else if (248 <= bChar && bChar < 252)
        {
            bOffLen = 5;
        }
        else if (252 <= bChar && bChar < 256)
        {
            bOffLen = 6;
        }
        else
        {
            //10xxxxxx段的理论上来说属于某个字符的一部分，不做处理
        }
        return bOffLen;
    }

    int char_to_int(char* pChar)
    {
        int n = 0;
        sscanf(pChar, "%x", &n);
        return n;
    }

    int bsl_url_decode(char *pOut, size_t uLen, const char *pData)
    {
        if (pData == NULL)
        {
            *pOut = '\0';
            return -1;
        }

        char szBuf[3];
        char *p = const_cast<char*>(pData);

        while (*p != 0)
        {
            if (uLen <= 1)
                break;

            if (*p == '%')
            {
                szBuf[0] = *(++p);
                szBuf[1] = *(++p);
                szBuf[2] = '\0';
                *pOut = char_to_int(szBuf);
            }
            else
            {
                *pOut = *p;
            }

            p++;
            pOut++;
            uLen--;
        }

        *pOut = '\0';
        return 0;
    }

    int bsl_url_encode(char *pOut, size_t uLen, const char *pData)
    {
        char hex[] = "0123456789ABCDEF";

        while (*pData)
        {
            char cc = *pData;
            if (cc >= 'A' && cc <= 'Z'
                || cc >= 'a' && cc <= 'z'
                || cc >= '0' && cc <= '9'
                || cc == '.'
                || cc == '_'
                || cc == '-'
                || cc == '*')
            {
                *pOut++ = cc;
            }
            else if (cc == ' ')
            {
                *pOut++ = '+';
            }
            else
            {
                unsigned char c = static_cast<unsigned char>(cc);
                *pOut++ = '%';
                *pOut++ = hex[c / 16];
                *pOut++ = hex[c % 16];
            }

            pData++;
        }

        return 0;
    }

    int bsl_get_value_from_url(char *szValue,
                               unsigned int uValueLen,
                               const char *szUrl,
                               const char *szKey)
    {
        const char *p = szUrl;
        unsigned short wKeyLen = strlen(szKey);
        unsigned short wUrlLen = strlen(szUrl);
        while (true)
        {
            p = strstr(p, szKey);
            if (p == NULL)
            {
                szValue[0] = '\0';
                return -1;
            }

            if (p != szUrl && *(p - 1) != '/' && *(p - 1) != '&')
            {
                p++;
                continue;;
            }

            if ((p + wKeyLen) >= (szUrl + wUrlLen) || *(p+wKeyLen) != '=')
            {
                p++;
                continue;
            }

            break;
        }

        int len = -1;
        while (*p && len < (int)uValueLen)
        {
            if (*p == '&')
            {
                break;
            }

            if (len == -1 && *p == '=')
            {
                len = 0;
                p++;
                continue;
            }

            if (len >= 0)
            {
                *(szValue + len++) = *p;
            }

            p++;
        }

        *(szValue + len) = '\0';
        return len;
    }

    int bsl_calc_char_cnt(char *str, char key)
    {
        if (str == NULL)
        {
            return NULL;
        }

        int nCnt = 0;
        while (*str != NULL)
        {
            if (*str == key)
            {
                nCnt++;
            }
            str++;
        }

        return nCnt;
    }

    int bsl_turn_specific_char(char *dst, unsigned int len, const char *src, const char symbol)
    {
        int cnt = 0;
        if (dst == NULL || src == NULL)
        {
            return -1;
        }

        if (strlen(src) > len)
        {
            return -2;
        }

        while (*src)
        {
            if (*src == symbol)
            {
                *dst++ = '\\';
                *dst = *src;
            }
            else
            {
                *dst = *src;
            }

            dst++;
            src++;
            cnt++;
        }

        *dst = '\0';
        return cnt;
    }

    int bsl_turn_back_specific_char(char *dst, unsigned int len, const char *src)
    {
        int cnt = 0;
        if (dst == NULL || src == NULL)
        {
            return -1;
        }

        if (strlen(src) > len)
        {
            return -2;
        }

        while (*src)
        {
            if (*src == '\\')
            {
                *dst = *(++src);
            }
            else
            {
                *dst = *src;
            }
            src++;
            dst++;
            cnt++;
        }

        *dst = '\0';
        return cnt;
    }

    unsigned int bsl_ip_str_2_num(const std::string &szIp)
    {
        int nIP1 = 0;
        int nIP2 = 0;
        int nIP3 = 0;
        int nIP4 = 0;
        sscanf(szIp.c_str(), "%d.%d.%d.%d", &nIP1, &nIP2, &nIP3, &nIP4);
        return (nIP1 << 24) + (nIP2 << 16) + (nIP3 << 8) + nIP4;
    }

    std::string bsl_ip_num_2_str(unsigned int uIp)
    {
        char szClientIP[32] = { 0 };
        snprintf(szClientIP, sizeof(szClientIP) - 1, "%u.%u.%u.%u",
                 uIp / (256 * 256 * 256),
                 uIp % (256 * 256 * 256) / (256 * 256),
                 uIp % (256 * 256) / 256,
                 uIp % 256);
        std::string szIp(szClientIP);
        return szIp;
    }

    int bsl_cmp_ver(std::string szVer1, std::string szVer2)
    {
        unsigned int uVer1_1 = 0;
        unsigned int uVer1_2 = 0;
        unsigned int uVer1_3 = 0;
        unsigned int uVer1_4 = 0;
        unsigned int uVer2_1 = 0;
        unsigned int uVer2_2 = 0;
        unsigned int uVer2_3 = 0;
        unsigned int uVer2_4 = 0;
        sscanf(szVer1.c_str(), "%u.%u.%u.%u", &uVer1_1, &uVer1_2, &uVer1_3, &uVer1_4);
        sscanf(szVer2.c_str(), "%u.%u.%u.%u", &uVer2_1, &uVer2_2, &uVer2_3, &uVer2_4);
        long long llVer1 = (uVer1_1 << 24) + (uVer1_2 << 16) + (uVer1_3 << 8) + uVer1_4;
        long long llVer2 = (uVer2_1 << 24) + (uVer2_2 << 16) + (uVer2_3 << 8) + uVer2_4;
        return llVer1 - llVer2;
    }

    bool bsl_utf8_have_emoji(const char *str)
    {
        int _offside = 1;
        for (int i = 0; i < strlen((char*)str); i += _offside)
        {
            unsigned char _tmp_c = (unsigned char)str[i];
            if (0 < _tmp_c && _tmp_c < 128)
            {
                _offside = 1;
            }
            else if (192 <= _tmp_c && _tmp_c < 224)
            {
                _offside = 2;
                
            }
            else if (224 <= _tmp_c && _tmp_c < 240)
            {
                _offside = 3;
            }
            else if (240 <= _tmp_c && _tmp_c < 248)
            {
                _offside = 4;
                return true;
            }
            else if (248 <= _tmp_c && _tmp_c < 252)
            {
                _offside = 5;
            }
            else if (252 <= _tmp_c && _tmp_c < 256)
            {
                _offside = 6;
            }
            else
            {
                //10xxxxxx段的理论上来说属于某个字符的一部分，不做处理
            }
        }
        return false;
    }

    unsigned int bsl_get_ver_num(std::string szVer)
    {
        unsigned int uVer1_1 = 0;
        unsigned int uVer1_2 = 0;
        unsigned int uVer1_3 = 0;
        unsigned int uVer1_4 = 0;
        sscanf(szVer.c_str(), "%u.%u.%u.%u", &uVer1_1, &uVer1_2, &uVer1_3, &uVer1_4);
        unsigned int llVer1 = (uVer1_1 << 24) + (uVer1_2 << 16) + (uVer1_3 << 8) + uVer1_4;
        return llVer1;
    }
}